"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.

openGauss is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

          http://license.coscl.org.cn/MulanPSL2

THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
"""
Case Type   : 数据库系统
Case Name   : 备机磁盘空间不足时，主机base数据量大于备机剩余空间
Create At   : 2020-7-7
Owner       : @peilinqian
Description :
    1、备机磁盘不足场景模拟（可以使用cfe故障注入方式）
    2、主机数据量大于备机剩余磁盘空间条件满足（主机进行大量数据插入，备机stop，主机继续插入完成）
    3、备机进行重建，重建失败，打印日志包含重建失败关键信息“No space left on device”
    4、恢复备机磁盘空间
    5、备机再次进行重建成功
Expect      :
    1、进行大文件构造，使备机磁盘空间不足
    2、主机进行大量数据插入，数据量高于备机磁盘剩余磁盘空间
    3、重建失败，提示信息正确
    4、恢复备机磁盘空间
    5、备机再次重建成功
History     :
    created: 2020/07/07  created by @peilinqian
    modified: 2021/12/14  modified by @wan005:优化断言和步骤
"""
import os
import time
import unittest

from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.CommonSH import RestartDbCluster
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class MyTest(unittest.TestCase):
    primary_sh = CommonSH("PrimaryDbUser")
    standby1_sh = CommonSH("Standby1DbUser")
    nodes_tuple = ("PrimaryDbUser", "Standby1DbUser", "Standby2DbUser")

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info("==Opengauss_Reliability_Dbsys_Case023.py start==")
        self.DB_INSTANCE_PATH = macro.DB_INSTANCE_PATH
        self.primary_root_node = Node(node="PrimaryRoot")
        self.primary_user_node = Node(node="PrimaryDbUser")
        self.standby1_root_node = Node(node="Standby1Root")
        self.standby1_user_node = Node(node="Standby1DbUser")
        self.standby2_user_node = Node(node="Standby2DbUser")
        self.com = Common()
        self.Constant = Constant()
        self.sqlfile = "reliability_dbsys022.sql"
        self.DB_DISK_NAME = ""

        text = "==get standby disk name =="
        self.log.info(text)
        cmd = f"df -h {macro.DB_INSTANCE_PATH}"
        self.log.info(cmd)
        msg = self.standby1_root_node.sh(cmd).result()
        self.log.info(msg)
        self.DB_DISK_NAME = msg.splitlines()[-1].split()[0].strip()
        self.log.info(self.DB_DISK_NAME)

        self.inject_cmd = f"rfile_full (diskname) " \
                          f"values ({self.DB_DISK_NAME})"
        self.clean_cmd = f"rfile_full  where(diskname={self.DB_DISK_NAME})"
        self.t_name = "t_db_system_023"

    def test_main(self):
        try:
            text = "备机大文件构造"
            self.log.info(text)
            availsize = self.com.getAvailSize(self.standby1_user_node,
                                              self.DB_INSTANCE_PATH)
            self.log.info(availsize)

            text = "--step1:备机磁盘不足场景模拟standby1 disk full;expect:成功"
            self.log.info(text)
            tmp = self.com.cfe_inject(self.standby1_root_node,
                                      self.inject_cmd)
            self.log.info(tmp)
            self.log.info("Available:" +
                          self.com.getAvailSize(self.standby1_user_node,
                                                self.DB_INSTANCE_PATH))

            self.log.info("目标主机新建路径")
            self.to_path = os.path.join(os.path.dirname
                                        (macro.DB_INSTANCE_PATH),
                                        "/test_script/")
            self.log.info(self.to_path)
            self.log.info("目标主机文件路径")
            self.newsql_path = os.path.join(self.to_path, self.sqlfile)
            self.log.info(self.newsql_path)
            self.log.info("拷贝文件")
            self.com.scp_file(self.primary_root_node,
                              self.sqlfile, self.to_path)

            text = "--step2:主机进行大量数据插入;expect:成功"
            self.log.info(text)
            create_cmd = f'''set synchronous_commit=on;
                        drop table if exists {self.t_name};
                        create table {self.t_name}(id int,name varchar(50),
                        name1 varchar(50),name2 varchar(50));'''
            create_msg = self.primary_sh.executDbSql(create_cmd)
            self.log.info(create_msg)
            self.com.file_sql_execute(self.primary_user_node,
                                      self.newsql_path, 100)

            text = "--step3:进行备机重建;" \
                   "expect:提示No space left on device/Unable to connect"
            self.log.info(text)
            msg = self.standby1_sh.executeGsctl("build",
                                                self.Constant.
                                                NO_SPACE_BUILD_FAIL_MSG,
                                                "-b full",
                                                get_detail=True)
            self.log.info(msg)
            self.assertTrue(self.Constant.NO_SPACE_BUILD_FAIL_MSG in msg
                            or "Unable to connect" in msg, "执行失败" + text)

        finally:
            self.log.info("--step4+5:备机磁盘恢复再次重建备机;expect:成功")
            self.log.info("==standby1 clean disk==")
            tmp = self.com.cfe_clean(self.standby1_root_node, self.clean_cmd)
            self.log.info(tmp)

            self.log.info("重建前打印剩余空间信息")
            self.log.info("Available:" +
                          self.com.getAvailSize(self.standby1_user_node,
                                                self.DB_INSTANCE_PATH))

            result = self.standby1_sh.executeGsctl("build",
                                                   self.Constant.
                                                   NO_SPACE_BUILD_FAIL_MSG1,
                                                   "-b full")
            self.log.info(result)
            text = "恢复后第一次重建可能失败，需要再次重建"
            self.log.info(text)
            if result:
                time.sleep(5)
                result = self.standby1_sh.executeGsctl("build",
                                                       self.Constant.
                                                       REBUILD_SUCCESS_MSG,
                                                       "-b full")
                self.log.info(result)
                self.assertTrue(result, "执行失败" + text)
            status = self.primary_sh.getDbClusterStatus("detail")
            self.log.info(status)
            self.assertTrue("Degraded" in status or "Normal" in status,
                            "执行失败" + text)

            self.log.info("校验备机是否完成数据同步")
            flag = self.standby1_sh.check_data_consistency()
            self.assertTrue(flag, "执行失败" + text)

            self.log.info("重建成功后判断插入完成主备数据一致")
            select_sql = f"select count(*) from {self.t_name};"
            nodes_tuple = (self.primary_user_node, self.standby1_user_node,
                           self.standby2_user_node)
            flag = self.com.check_data_sample_by_all(select_sql, *nodes_tuple)
            self.assertTrue(flag, "执行失败" + text)

    def tearDown(self):
        text = "删除测试数据,恢复环境"
        self.log.info(text)
        self.log.info("==standby1 clean disk==")
        tmp = self.com.cfe_clean(self.standby1_root_node, self.clean_cmd)
        self.log.info(tmp)
        drop_sql = f"drop table {self.t_name}"
        self.assertTrue("DROP TABLE" in self.primary_sh.executDbSql(drop_sql)
                        , "执行失败" + text)
        self.log.info("==Opengauss_Reliability_Dbsys_Case023.py finish==")
